<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        // 单例模式的好处在于对代码的组织作用，将相关的属性和方法封装在一个不会被多次实例化的对象中，让代码的维护和调试更加轻松。
        // 隐藏了实现细节，可以防止被错误修改，还防止了全局命名空间的污染。另外可以通过惰性加载提高性能，减少不必要的内存消耗。

        //【1】最简单的单例模式起始就是一个对象字面量，它将有关联的属性和方法组织到一起。/这种形式的单例模式，所有成员都是公开的，都可以通过singleton来访问。不够安全
        var singleton = {
                prop: "value",
                method: function() {}
            }
            //【2】包含私有成员的单例模式。这种单例对象的私有变量，只能在函数内部或通过暴露出来的方法去访问这个私有变量。这种形式又被成为模块模式。
        var singleton = (function() {
            var privateVar = "private";
            return {
                prop: "value",
                method: function() {
                    console.log(privateVar);
                }
            }
        })();
        //【3】惰性实例化：
        // 不管是直接字面量或者私有成员的单例模式，前两者都是在脚本加载时就被创建出来的单例，但是有时候，页面可能永远也用不到这个单例对象，应该做到使用时候才去创建。
        // 首先将创建单例对象的代码封装到init函数中，然后声明一个私有变量instance表示单例对象的实例，公开一个方法getInstance来获取单例对象。
        // 调用的时候就通过singleton.getInstance()来进行调用，单例对象是在调用getInstance的时候才真正被创建。

        // 单例模式是JS中最常使用的设计模式，从增强模块性和代码组织性等方面来说，应该尽可能的使用单例模式。它可以把相关代码组织到一起便于维护，
        // 对于大型项目，每个模块惰性加载可以提高性能，隐藏实现细节，暴露出常用的api。常见的类库比如underscore，jQuery我们都可以将其理解为单例模式的应用。
        var singleton = (function() {
            function init() {
                var privateVar = "private";
                return {
                    prop: "value",
                    method: function() {
                        console.log(privateVar);
                    }
                }
            }
            var instance = null;
            return {
                getInstance: function() {
                    if (!instance) {
                        instance = init();
                    }
                    return instance;
                }
            }
        })();
        //【4】结合实战：下面的代码主要实现一个简单的日期帮助类，通过单例模式实现：
        //【4-1】这段代码通过对象字面量实现单例模式，使用的时候直接调用方法即可。
        var dateTimeHelper = {
            now: function() {
                return new Date();
            },
            format: function(date) {
                return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
            }
        };
        console.log(dateTimeHelper.now());
        //【4-2】惰性加载实现单例模式
        var dateTimeHelper = (function() {
            function init() {
                return {
                    now: function() {
                        return new Date();
                    },
                    format: function(date) {
                        return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
                    }
                }
            }
            var instance = null;
            return {
                getInstance: function() {
                    if (!instance) {
                        instance = init();
                    }
                    return instance;
                }
            }
        })();
        console.log(dateTimeHelper.getInstance().now())
    </script>
</body>

</html>